#!/usr/bin/python3
# -*- coding: UTF-8 -*-

import tkinter as tk
import threading
import time
import socketserver
import json
import voice
import database as db
import config


# 区域标签字体大小
areaFontSize = 12

# 货物字体大小
stuffFontSize = 8

# 区域标签的长宽尺寸
# 因为区域标签的字体大，所以区域标签和货物标签相同的尺寸，最终会以区域标签最为最终大小
areaLabelWidthSize = 4
areaLabelHightSize = 3

# 货物标签的长宽尺寸
stuffWidth = 4
stuffHight = 4

# 货物编号标签的长宽尺寸
indexWidth = 5
indexHight = 1
passageHight = 3


class Area(object):
    """docstring for Area"""
    def __init__(self, window, area, pos_r, pos_c, r_span, c_span):
        super(Area, self).__init__()

        self.label = tk.Label(window, 
                            text = "%s\n\n区" % (area.upper()),
                            font = ('Arial', areaFontSize),
                            bg = 'SlateGray',
                            width = stuffWidth,
                            height = stuffHight, )
        self.label.grid(row = pos_r, 
                        rowspan = r_span,
                        columnspan = c_span,
                        column = pos_c, 
                        sticky = tk.N + tk.S)


class Passage(object):
    """docstring for Passage"""
    def __init__(self, window, text, pos_r, pos_c, color, high):
        super(Passage, self).__init__()

        if color:
            self.label = tk.Label(window, 
                                text = text,
                                font = ('Arial', stuffFontSize),
                                bg = color,
                                width = indexWidth,
                                height = high, )
        else:
            self.label = tk.Label(window, 
                                text = text,
                                font = ('Arial', stuffFontSize),
                                width = indexWidth,
                                height = high, )

        self.label.grid(row = pos_r, 
                        column = pos_c, 
                        sticky = tk.N + tk.S)


class Stuff(object):
    """docstring for Stuff"""
    def __init__(self, window, pos_r, pos_c, stuff):
        super(Stuff, self).__init__()

        if stuff:
            self.label = tk.Label(window, 
                                text = "",
                                font = ('Arial', stuffFontSize),
                                bg = 'red',
                                width = stuffWidth,
                                height = stuffHight,
                                # 边框
                                highlightbackground = "black",
                                highlightthickness = 1 )
        else:
            self.label = tk.Label(window, 
                                font = ('Arial', stuffFontSize),
                                width = stuffWidth,
                                height = stuffHight)
            

        self.label.grid(row = pos_r, 
                        column = pos_c, 
                        sticky = tk.N + tk.S)

    def SetOnline(self, name):
        self.label.configure(bg = 'green')
        if name:
            self.label.config(text = name)

    def SetOffline(self):
        self.label.configure(bg = 'red')
        self.label.config(text = "")


def ParseClientInfo(data):
    # print(data)
    info_dict = json.loads(data)
    print(info_dict)

    if 'area' in info_dict and 'num' in info_dict and 'dir' in info_dict:
        area = ord(info_dict['area']) - ord('A')
        index = info_dict['num'] - 1
        direct = info_dict['dir']

        if 'prod' in info_dict:
            name = info_dict['prod']
        else:
            name = None

        print("area %d index %d direct %d name %s" % (area, index, direct, name))

        if direct:
            stuff[area][index].SetOnline(name)
            db.UpdateIntoTable(config.DB_NAME, area, index, name)
        else:
            stuff[area][index].SetOffline()
            db.DeleteFromTable(config.DB_NAME, area, index)

        voice.Play(info_dict['area'], info_dict['num'], info_dict['dir'])
    else:
        print("not contain 'area' or 'num' or 'dir'")


class QRCodeRecv(socketserver.BaseRequestHandler):
    def handle(self):
        try:
            while True:
                self.data = self.request.recv(1024)
                # print("{} send:".format(self.client_address), self.data)
                if not self.data:
                    print("connection lost")
                    break
                    
                ParseClientInfo(bytes.decode(self.data))
                # self.request.sendall(self.data.upper())
        except Exception as e:
            print(self.client_address, "disconnect")
        finally:
            self.request.close()

    def setup(self):
        print("before handle, connect with", self.client_address)

    def finish(self):
        print("finish run after handle")


class ServiceThread(threading.Thread):
    """docstring for ServiceThread"""
    def __init__(self):
        super(ServiceThread, self).__init__()
    
    def run(self):
        print("start tcp server")

        addr = ("localhost", 8080)
        self.svr = socketserver.TCPServer(addr, QRCodeRecv)
        self.svr.serve_forever()
        print("serve_forever shutdown")

    def stop_svr(self):
        print("stop tcp server")
        self.svr.shutdown()


try:
    window = tk.Tk()
    window.title('仓库存货 - 看板')

    # 全屏
    # window.attributes("-fullscreen", True)
    
    w = window.winfo_screenwidth()
    h = window.winfo_screenheight()
    window.geometry("%dx%d" % (w, h))

    # ======== Area Map - Start ========

    row = 0
    stuff = [[]]

    # Area A
    Area(window, 'A', row, 0, 2, 1)
    Passage(window, '', row + 2, 0, None, passageHight)

    for i in range(0, 53):
        stuff[0].append(Stuff(window, row, i + 1, True))
        Passage(window, "%03d" % (i + 1), row + 1, i + 1, "PaleGreen", indexHight)

    row += 3

    # Area B
    stuff.append([])

    Area(window, 'B', row, 0, 6, 1)
    Passage(window, '', row + 6, 0, None, passageHight)

    index = 1
    for i in range(0, 138):
        rowDiff = (i % 3) * 2
        columeDiff = int(i / 3)

        if i in [69, 70, 71, 72, 73, 74]:
            Stuff(window, row + rowDiff, columeDiff + 1, False)
        else:
            stuff[1].append(Stuff(window, row + rowDiff, columeDiff + 1, True))
            Passage(window, "%03d" % index, row + 1 + rowDiff, columeDiff + 1, "PaleGreen", indexHight)
            index += 1

    row += 7

    # Area C
    stuff.append([])

    Area(window, 'C', row, 0, 6, 1)
    Passage(window, '', row + 6, 0, None, passageHight)

    index = 1
    for i in range(0, 156):
        rowDiff = (i % 3) * 2
        columeDiff = int(i / 3)

        if i in [69, 70, 71, 72, 73, 74]:
            Stuff(window, row + rowDiff, columeDiff + 1, False)
        else:
            stuff[2].append(Stuff(window, row + rowDiff, columeDiff + 1, True))
            Passage(window, "%03d" % index, row + 1 + rowDiff, columeDiff + 1, "PaleGreen", indexHight)
            index += 1

    row += 7

    # Area D
    stuff.append([])

    Area(window, 'D', row, 0, 4, 1)
    Passage(window, '', row + 4, 0, None, passageHight)

    index = 1
    for i in range(0, 108):
        rowDiff = (i % 2) * 2
        columeDiff = int(i / 2)

        if i in [46, 47, 48, 49]:
            Stuff(window, row + rowDiff, columeDiff + 1, False)
        else:
            stuff[3].append(Stuff(window, row + rowDiff, columeDiff + 1, True))
            Passage(window, "%03d" % index, row + 1 + rowDiff, columeDiff + 1, "PaleGreen", indexHight)
            index += 1

    row += 5

    # Area E 
    stuff.append([])

    Area(window, 'E', row, 0, 2, 1)
    Passage(window, '', row + 2, 0, None, passageHight)

    for i in range(0, 54):
        stuff[4].append(Stuff(window, row, i + 1, True))
        Passage(window, "%03d" % (i + 1), row + 1, i + 1, "PaleGreen", indexHight)

    row += 3

    # ======== Area Map - End ========

    # ======== DataBase - Start ========

    db.CreateTable(config.DB_NAME)

    t_list = db.SelectTableAll(config.DB_NAME)
    print(t_list)

    for row in t_list:
        print(row)
        if row[0] > len(stuff):
            print("Area %d invalid maximum %d" % (row[0], len(stuff)))
            continue

        if row[1] > len(stuff[row[0]]):
            print("Area %d index %d invalid maximum %d" % (row[0], row[1], len(stuff[row[0]])))
            continue

        if row[2] != "None":
            stuff[row[0]][row[1]].SetOnline(row[2])
        else:
            stuff[row[0]][row[1]].SetOnline('')

    # ======== DataBase - End ========

    service = ServiceThread()
    service.start()
    print("server thread running...")

    # Only for test
    # stuff[0][0].SetOnline("0x0")
    # stuff[1][1].SetOnline("HSD\n10123\nCZJ")
    # stuff[2][2].SetOnline("2x2")
    # stuff[3][3].SetOnline("3x3")
    # stuff[4][4].SetOnline("4x4")

    window.mainloop()

    service.stop_svr()
    service.join()


except Exception as e:
    raise e

finally:
    pass
